﻿/*************************************************************************
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CatchUpTv.Tv;
using log4net;
using System.Net;
using System.Xml.Linq;
using Newtonsoft.Json;
using CatchUpTv.Utilities;
using CatchUpTv.Downloader.Rtmp;

namespace CatchUpTv.Downloader.Australia.AbcIView
{
    /// <summary>
    /// A downloader for ABC's iView.
    /// </summary>
    public class AbcIViewDownloader : IDownloader
    {
        /// <summary>
        /// The logger for this class.
        /// </summary>
        static ILog log = LogManager.GetLogger(typeof(AbcIViewDownloader));

        /// <summary>
        /// The configuration.
        /// </summary>
        Lazy<Configuration> _configuration = new Lazy<Configuration>(delegate
        {
            return new Configuration();
        });

        public AbcIViewDownloader()
        {
            Channels = new Lazy<IEnumerable<Channel>>(GetChannels);
            Shows = new Lazy<IEnumerable<Show>>(GetShows);
        }

        /// <summary>
        /// The list of channels this downloader can download from.
        /// </summary>
        public Lazy<IEnumerable<Channel>> Channels { get; set; }

        /// <summary>
        /// The list of shows this downloader can download from.
        /// </summary>
        public Lazy<IEnumerable<Show>> Shows { get; set; }

        /// <summary>
        /// The Id for this downloader.
        /// </summary>
        public string Id { get { return "ABC_iView"; } }

        /// <summary>
        /// The name for this downloader.
        /// </summary>
        public string Name { get { return "ABC iView"; } }

        /// <summary>
        /// The image URL for this downloader.
        /// </summary>
        public string ImageUrl { get { return "http://upload.wikimedia.org/wikipedia/en/thumb/7/75/Australian_Broadcasting_Corporation.svg/240px-Australian_Broadcasting_Corporation.svg.png"; } }

        /// <summary>
        /// Gets the list of iView channels.
        /// </summary>
        /// <returns>The list of channels.</returns>
        protected virtual IEnumerable<Channel> GetChannels()
        {
            WebClient webClient = new WebClient();

            // Get the iView configuration details
            var rawChannelXml = webClient.DownloadString(BaseUrl + _configuration.Value.ChannelsUrl);

            if (log.IsDebugEnabled)
            {
                log.DebugFormat("Channels XML: '{0}'", rawChannelXml);
            }

            var channelXml = XDocument.Parse(rawChannelXml);

            var categories = channelXml
                .Descendants("category")
                .Select(e => new Category(_configuration.Value)
                    {
                        Id = e.Attribute("id").Value,
                        Name = e.Element("name").Value,
                        Genre = e.Attributes().Any(a => a.Name == "genre" && a.Value == "true")
                    });

            var nonGenreCategories = categories.Where(c => c.Genre == false);

            IList<Channel> channels = new List<Channel>();

            foreach (Category category in nonGenreCategories)
            {
                channels.Add(new Channel()
                {
                    Id = "ABC_iView_catetory_" + category.Id,
                    Tag = category,
                    Name = category.Name,
                    Shows = new Lazy<IEnumerable<Show>>(category.GetShows)
                });
            }

            return channels;
        }

        /// <summary>
        /// Gets the list of iView shows.
        /// </summary>
        /// <returns>The list of shows.</returns>
        protected virtual IEnumerable<Show> GetShows()
        {
            return Channels.Value.SelectMany(c => c.Shows.Value);
        }

        /// <summary>
        /// Downloads the given episode.
        /// </summary>
        /// <param name="episode">The episode to download.</param>
        /// <returns>The local path to the downloaded episode</returns>
        public string DownloadEpisode(Episode episode)
        {
            return DownloadEpisode(episode, new Action<double, double>(delegate { }));
        }

        /// <summary>
        /// Downloads the given episode.
        /// </summary>
        /// <param name="episode">The episode to download.</param>
        /// <param name="progressListener">The progress listener that will recieve percentage and size updates.</param>
        /// <returns>The local path to the downloaded episode</returns>
        public string DownloadEpisode(Episode episode, Action<double, double> progressListener)
        {
            SeriesEpisode seriesEpisode = episode.Tag as SeriesEpisode;

            // Check that the episode is an iView episode
            if (seriesEpisode == null)
            {
                throw new ArgumentException("The given episode doesn't seem to be an ABC iView episode.");
            }

            var authToken = new AuthenticationToken(_configuration.Value);

            string file = seriesEpisode.File.Substring(seriesEpisode.File.LastIndexOf('/') + 1);            
            string extension = seriesEpisode.File.Substring(seriesEpisode.File.LastIndexOf('.') + 1);            

            if (extension != "mp4" && extension != "flv")
            {
                throw new NotSupportedException(string.Format("Unknown extension: {0}", extension));
            }

            RtmpDownloader rtmp = new RtmpDownloader();

            if (authToken.Host == "hostworks")
            {
                rtmp.RtmpUrl = string.Format("rtmp://203.18.195.10/ondemand?auth=\"{0}\"", authToken.Token);
                rtmp.OutputFile = file;
                rtmp.PlaybackPath = extension + ":" + seriesEpisode.File;
                rtmp.SwfPlayerUrl = "http://www.abc.net.au/iview/images/iview.jpg";                
            }
            else if (authToken.Host == "akamai")
            {
                rtmp.RtmpUrl = string.Format("rtmp://203.18.195.10/ondemand?auth=\"{0}\"", authToken.Token);
                rtmp.OverrideUrl = string.Format("rtmp://cp53909.edgefcs.net/ondemand?auth=\"{0}\"", authToken.Token);
                rtmp.OutputFile = file;
                rtmp.PlaybackPath = extension + ":" + seriesEpisode.File;
            }
            else
            {
                throw new NotSupportedException(string.Format("Unknown host: {0}", authToken.Host));
            }

            rtmp.DownloadVideo(progressListener);

            return file;
        }

        /// <summary>
        /// The iView base URL.
        /// </summary>
        public const string BaseUrl = "http://www.abc.net.au/iview/";
    }
}
